home *** CD-ROM | disk | FTP | other *** search
- /**\
- |**| HappyTrails.c
- \**/
-
- #include <stdio.h>
- #include <stdarg.h>
-
- #include "HappyTrails.h"
-
- // typdef's, struct's, define's, enum's, etc.
-
- #define kMPStackSize 0 // use default stack size
- #define kMPTaskOptions 0 // use no options
-
- enum
- {
- mAppleMenu = 128,
- iAboutBox = 1,
- mFileMenu = 129,
- iQuit = 1,
- mTasksMenu = 130,
- mWeightMenu = 131
- };
-
- typedef struct BallStruct {
- Point fPosition;
- Point fDelta;
- RGBColor fColor;
- UInt32 fLength;
- } BallRec,*BallPtr,**BallHdl;
-
- typedef struct MyTaskStruct {
- MPTaskID fTaskID;
- MPTaskWeight fWeight;
- MPSemaphoreID fSemaphoreID;
- Rect fBounds;
- UInt32 fIndex;
- UInt32 fBallNum;
- BallPtr fBallPtr;
- }MyTaskRec,*MyTaskPtr,**MyTaskHdl;
-
- // external globals
-
- UInt32 gNumTasks = 0;
-
- // local (static) globals
-
- static PixMapHandle gWindowPixMap = nil;
- static UInt8* gWindowBasePtr = nil;
-
- static GWorldPtr gOffscreenPtr = nil;
- static Rect gOffscreenRect = {0,0,kBallHeight,kBallWidth};
- static PixMapHandle gOffscreenPixMap = nil;
- static UInt8* gOffscreenBasePtr = nil;
-
- static Boolean gPaused = false;
- static Boolean gLoop = true;
-
- static MyTaskPtr gMyTaskPtrs = nil;
- static MPQueueID gNotificationQueueID;
-
- static MenuHandle gContextualMenuHdl = nil;
-
- // local function prototypes
-
- static OSStatus Ball_Task(void* pMyTaskPtr);
-
- static OSStatus New_Ball(MyTaskPtr pMyTaskPtr);
- static void Draw_Ball(const Rect* pRectPtr,const RGBColor* pBallColorPtr);
- static void Blit_Ball(const Rect *pBallRect,const RGBColor* pBallColorPtr);
-
- static Boolean rects_Intersect(const Rect* pRect1,const Rect* pRect2);
- static void offset_rect (Rect *r,const short dh,const short dv);
- static SInt16 random();
-
- #define ABS(x) ((x) < 0 ? -(x) : (x))
-
- // local functions
-
-
- /**\
- |**| MPGetTaskWeight
- \**/
-
- static pascal OSStatus MPGetTaskWeight(MPTaskID task,MPTaskWeight* weight)
- {
- MPTaskInfo tMPTaskInfo;
- OSStatus error;
-
- if (!weight) return paramErr;
-
- tMPTaskInfo.version = kMPTaskInfoVersion;
-
- error = MPExtractTaskState(task,kMPTaskStateTaskInfo,(void*) &tMPTaskInfo);
-
- if (error == noErr)
- *weight = tMPTaskInfo.weight;
-
- return error;
- }
-
- /**\
- |**| printf to debugger
- \**/
-
- static int dprintf(const char *format,...)
- {
- char buffer[257]; /* [length byte] + [255 string bytes] + [null] */
- va_list arglist;
- int return_value = 0;
-
- va_start(arglist, format);
- return_value = vsprintf(buffer, format, arglist);
- va_end(arglist);
-
- #if TARGET_API_MAC_CARBON
- CopyCStringToPascal(buffer,(unsigned char*) buffer);
- DebugStr((unsigned char*) buffer);
- #else
- debugstr(buffer);
- #endif TARGET_API_MAC_CARBON
-
- return return_value;
- }
-
-
- /**\
- |**| convert index (1 <-> gNumTasks) to weight
- \**/
-
- static MPTaskWeight TaskToWeight(UInt32 pTaskIndex)
- {
- float_t e = exp(1); // 2.718281828;
- if (gNumTasks <= 1)
- return 100;
- else
- return (50 * (pow(e,(log(200) * pTaskIndex) / (gNumTasks - 1))));
- }
-
- /**\
- |**| Initialize everything for HappyTrails, make sure we can run
- \**/
-
- OSStatus HT_Init(UInt32 pNumTasks)
- {
- OSStatus error;
- UInt32 index;
-
- if (!MPLibraryIsLoaded())
- return kMPInsufficientResourcesErr;
-
- gLoop = true;
- gNumTasks = pNumTasks;
- #if TARGET_API_MAC_CARBON
-
- gWindowPixMap = GetPortPixMap(GetWindowPort(gWindowPtr));
- #else
- gWindowPixMap = ((CWindowPtr) gWindowPtr)->portPixMap;
- #endif TARGET_API_MAC_CARBON
-
- if (!LockPixels(gWindowPixMap))
- DebugStr("\p|HT_Init-F-LockPixels(gWindowPixMap) error.;es");
-
- gWindowBasePtr = (UInt8*) GetPixBaseAddr(gWindowPixMap);
-
- {
- RGBColor whiteRGBColor = {-1,-1,-1};
- CGrafPtr savePort;
- GDHandle saveGDHdl;
-
- GetGWorld(&savePort, &saveGDHdl);
-
- // Create an offscreen GWorld and draw our SillyBall into it.
- // The MP tasks will copy from this GWorlds PixMap to our
- // windows PixMap changing the color on-the-fly.
-
- error = NewGWorld(&gOffscreenPtr, 1, &gOffscreenRect, nil, nil, keepLocal);
- if (error != noErr)
- dprintf("|HT_Init-F-NewGWorld error: %d.;es",error);
-
- gOffscreenPixMap = GetGWorldPixMap(gOffscreenPtr);
- if (!LockPixels(gOffscreenPixMap))
- DebugStr("\p|HT_Init-F-LockPixels(gOffscreenPixMap) error.;es");
-
- gOffscreenBasePtr = (UInt8*) GetPixBaseAddr(gOffscreenPixMap);
-
- SetGWorld(gOffscreenPtr, nil);
- EraseRect(&gOffscreenRect);
- Draw_Ball(&gOffscreenRect,&whiteRGBColor);
-
- SetGWorld(savePort, saveGDHdl);
- }
-
- // Initialize remaining globals
- gNotificationQueueID = NULL;
-
- // create the notification queue
- error = MPCreateQueue(&gNotificationQueueID);
- if (error != noErr)
- {
- dprintf("|HT_Init-F-MPCreateQueue(&gNotificationQueueID) error: %d.;g",error);
- return error;
- }
-
- // allocate the task records
- gMyTaskPtrs = (MyTaskPtr) NewPtrClear(sizeof(MyTaskRec) * gNumTasks);
- if (!gMyTaskPtrs)
- {
- error = MemError();
- if (error == noErr)
- error = memFullErr;
- return error;
- }
-
- {
- UInt16 width = gWindowRect.right - gWindowRect.left;
- UInt16 height = gWindowRect.bottom - gWindowRect.top;
- UInt16 rows,cols;
-
- cols = sqrt(gNumTasks * 4 / 3);
- rows = gNumTasks / cols;
-
- if ((rows * cols) < gNumTasks)
- rows++;
-
- width /= cols;
- height /= rows;
-
- EraseRect(&gWindowRect);
-
- for (index = 0; (index < gNumTasks) && (error == noErr); index++)
- {
- MyTaskPtr tMyTaskPtr = &gMyTaskPtrs[index];
- Rect tRect;
-
- tRect.bottom = (tRect.top = height * (index / cols)) + height;
- tRect.right = (tRect.left = width * (index % cols)) + width;
-
- FrameRect(&tRect);
-
- tMyTaskPtr->fBounds = tRect;
- tMyTaskPtr->fWeight = TaskToWeight(index); // 16 * (1 << index);
- tMyTaskPtr->fIndex = index;
-
- tMyTaskPtr->fBallPtr = (BallPtr) NewPtrClear(sizeof(BallRec) * kNumBalls);
-
- # if !SMP_TEST
- error = MPCreateTask(Ball_Task, tMyTaskPtr, // task entry point & parameter
- kMPStackSize, gNotificationQueueID, // stack size & notification queue ID
- tMyTaskPtr, NULL, kMPTaskOptions, // Notify params 1 & 2 and task options
- &tMyTaskPtr->fTaskID); // task id
- if (error != noErr)
- {
- dprintf("|HT_Init-F-MPCreateTask error: %d.;g",error);
- return error;
- }
-
- error = MPSetTaskWeight(tMyTaskPtr->fTaskID,tMyTaskPtr->fWeight);
- if (error != noErr)
- {
- dprintf("|HT_Init-F-MPSetTaskWeight error: %d.;g",error);
- return error;
- }
-
-
- // create the ready Semaphore
- error = MPCreateSemaphore(1,1,&tMyTaskPtr->fSemaphoreID);
- if (error != noErr)
- {
- dprintf("|HT_Init-F-MPCreateSemaphore error: %d.;g",error);
- return error;
- }
-
- # endif !SMP_TEST
- }
- }
-
- gContextualMenuHdl = GetMenu(mWeightMenu);
- InsertMenu(gContextualMenuHdl, -1);
-
- // If something went wrong, just go back to single processor mode
- if (error != noErr)
- gNumTasks = 1;
-
- return error;
- } // HT_Init
-
- /**\
- |**| Cleanup everything
- \**/
-
- void HT_Term(void)
- {
- OSStatus error;
- UInt32 index;
-
- gInBackGround = gLoop = false;
-
- if (gMyTaskPtrs)
- {
- for (index = 0; index < gNumTasks; index++)
- {
- MyTaskPtr tMyTaskPtr = &gMyTaskPtrs[index];
- if (tMyTaskPtr->fTaskID != NULL)
- {
- // terminate this task
- error = MPTerminateTask(tMyTaskPtr->fTaskID, kMPTaskAbortedErr);
- if (error != noErr)
- dprintf("|HT_Term-F-MPTerminateTask error: %d.;g",error);
-
- // Now wait for notification that this task has terminated
- while ((error = MPWaitOnQueue(gNotificationQueueID,
- (void*) &tMyTaskPtr, NULL, NULL, kDurationImmediate)) == noErr)
- {
- if (tMyTaskPtr->fTaskID != NULL)
- {
- tMyTaskPtr->fTaskID = NULL;
-
- if (tMyTaskPtr->fBallPtr)
- DisposePtr((Ptr) tMyTaskPtr->fBallPtr);
- tMyTaskPtr->fBallPtr = nil;
- }
- }
-
- // delete the ready Semaphore
- if (tMyTaskPtr->fSemaphoreID != NULL)
- {
- MPDeleteSemaphore(tMyTaskPtr->fSemaphoreID);
- tMyTaskPtr->fSemaphoreID = NULL;
- }
- }
- }
-
- // delete the notification queue
- if (gNotificationQueueID != NULL)
- {
- MPDeleteQueue(gNotificationQueueID);
- gNotificationQueueID = NULL;
- }
-
- // delete the task data
- DisposePtr((Ptr)gMyTaskPtrs);
- gMyTaskPtrs = NULL;
- }
-
- if (gOffscreenPtr)
- DisposeGWorld(gOffscreenPtr);
- gOffscreenPtr = nil;
- }
-
- /**\
- |**| Handle a null event
- \**/
-
- void HT_DoNull(void)
- {
- static Boolean sInBackGround = false;
- # if SMP_TEST
- UInt32 index;
-
- gLoop = false;
- for (index = 0; index < gNumTasks;index++)
- Ball_Task((void*) &gMyTaskPtrs[index]);
- # else
- // MPYield();
- # endif SMP_TEST
-
- if (sInBackGround != gInBackGround)
- {
- sInBackGround = gInBackGround;
- if (!sInBackGround)
- {
- SInt32 index;
- for (index = 0; index < gNumTasks;index++)
- MPSignalSemaphore(gMyTaskPtrs[index].fSemaphoreID);
- }
- }
- }
-
- /**\
- |**| Handle a mouse down event
- \**/
-
- void HT_DoClick(const EventRecord *pEventPtr)
- {
- MyTaskPtr tMyTaskPtr = nil;
- Point where = pEventPtr->where;
- UInt32 index;
-
- GlobalToLocal(&where);
-
- for (index = 0;index < gNumTasks;index++)
- {
- if (PtInRect(where,&gMyTaskPtrs[index].fBounds))
- tMyTaskPtr = &gMyTaskPtrs[index];
- }
-
- if (!tMyTaskPtr || !gContextualMenuHdl)
- goto beep;
-
- {
- SInt32 weight = (SInt32) tMyTaskPtr->fWeight;
- SInt16 count = CountMenuItems(gContextualMenuHdl);
- Boolean first = true;
- #if 1
- SInt32 value;
-
- for (index = 1;index <= count;index++)
- {
- Str255 tStr255;
- UInt32 temp = gNumTasks;
-
- gNumTasks = count;
- value = TaskToWeight(index - 1);
- gNumTasks = temp;
-
- NumToString(value, tStr255);
- SetMenuItemText(gContextualMenuHdl, index, tStr255);
- #if CALL_NOT_IN_CARBON
- EnableItem(gContextualMenuHdl, index);
- #else
- EnableMenuItem(gContextualMenuHdl, index);
- #endif CALL_NOT_IN_CARBON
-
- if (value < weight)
- CheckMenuItem(gContextualMenuHdl, index, false);
- else
- {
- CheckMenuItem(gContextualMenuHdl, index, first);
- if (first)
- weight = value;
- first = false;
- }
- }
-
- if (IsShowContextualMenuClick(pEventPtr))
- {
- UInt32 outUserSelectionType;
- SInt16 outMenuID;
- UInt16 outMenuItem;
- OSStatus tOSStatus;
-
- gPaused = true;
- tOSStatus = ContextualMenuSelect(gContextualMenuHdl,
- pEventPtr->where,
- false,
- nil,
- nil,
- nil,
- &outUserSelectionType,
- &outMenuID,
- &outMenuItem);
- gPaused = false;
- if ((tOSStatus == noErr) && (outUserSelectionType == kCMMenuItemSelected))
- {
- if (outMenuID == mWeightMenu)
- {
- Str255 tStr255;
- OSStatus error;
-
- GetMenuItemText(gContextualMenuHdl, outMenuItem, tStr255);
- StringToNum(tStr255, &value);
- tMyTaskPtr->fWeight = value;
-
- index = (long) tMyTaskPtr->fIndex;
-
- error = MPSetTaskWeight(tMyTaskPtr->fTaskID, value);
- if (error != noErr)
- dprintf("|HT_DoClick-F-MPSetTaskWeight error: %d.;g",error);
- }
- }
- return;
- }
- else
- #endif
- {
- if (pEventPtr->modifiers & optionKey)
- EraseRect(&gWindowRect);
- else
- EraseRect(&tMyTaskPtr->fBounds);
- return;
- // goto beep;
- }
- }
- beep:
- SysBeep(15);
- }
-
- /**\
- |**| This is the MP task entrypoint
- \**/
-
- OSStatus Ball_Task(void* pMyTaskPtr)
- {
- MyTaskPtr tMyTaskPtr = (MyTaskPtr) pMyTaskPtr;
-
- // wait for the ready Semaphore
- MPWaitOnSemaphore(tMyTaskPtr->fSemaphoreID,kDurationForever);
-
- do {
- New_Ball(tMyTaskPtr);
- while (gInBackGround)
- {
- // wait for the ready Semaphore
- MPWaitOnSemaphore(tMyTaskPtr->fSemaphoreID,kDurationForever);
- }
- } while (gLoop);
- return noErr;
- }
-
- /**\
- |**| Draw the next ball
- \**/
-
- static OSStatus New_Ball(MyTaskPtr pMyTaskPtr)
- {
- Rect ballRect;
- Rect bounds = pMyTaskPtr->fBounds;
- UInt32 newLeft,newTop;
- UInt32 width = bounds.right - bounds.left;
- UInt32 height = bounds.bottom - bounds.top;
- RGBColor ballColor;
-
- BallPtr tBallPtr;
-
- if (pMyTaskPtr->fBallNum >= kNumBalls)
- pMyTaskPtr->fBallNum = 0;
-
- if (gPaused)
- return noErr;
-
- tBallPtr = &pMyTaskPtr->fBallPtr[pMyTaskPtr->fBallNum++];
-
- if (tBallPtr->fLength)
- {
- newTop = tBallPtr->fPosition.v;
- newLeft = tBallPtr->fPosition.h;
-
- ballRect.bottom = (ballRect.top = newTop) + kBallHeight;
- ballRect.right = (ballRect.left = newLeft) + kBallWidth;
-
- ballColor = tBallPtr->fColor;
- if (tBallPtr->fLength == 1)
- {
- ballColor.red ^= 0x8000;
- ballColor.green ^= 0x8000;
- ballColor.blue ^= 0x8000;
- }
- }
- else
- {
- //
- // Make a random new color for the ball.
- //
- ballColor.red = (unsigned short) random();
- ballColor.green = (unsigned short) random();
- ballColor.blue = (unsigned short) random();
- tBallPtr->fColor = ballColor;
-
- //
- // Make a random new location for the ball, that is normalized to the window size.
- // This makes the Integer from random into a number that is 0..bounds.bottom
- // and 0..bounds.right. They are normalized so that we don't spend most of our
- // time drawing in places outside of the window.
- //
- do
- {
- newTop = 32767 + random(); newLeft = 32767 + random();
- newTop = bounds.top + ((newTop * (height - kBallHeight)) / 65536);
- newLeft = bounds.left + ((newLeft * (width - kBallWidth)) / 65536);
-
- ballRect.bottom = (ballRect.top = newTop) + kBallHeight;
- ballRect.right = (ballRect.left = newLeft) + kBallWidth;
-
- } while ( (ballRect.top < bounds.top) ||
- (ballRect.left < bounds.left) ||
- (ballRect.bottom >= bounds.bottom) ||
- (ballRect.right >= bounds.right)
- );
-
- //
- // Make a random new delta direction
- //
-
- do {
- tBallPtr->fDelta.h = random() % 5;
- tBallPtr->fDelta.v = random() % 5;
- } while ((tBallPtr->fDelta.h == 0) || (tBallPtr->fDelta.v == 0));
-
- tBallPtr->fLength = 0x3F & random(); // width + ABS(random() % height);
- }
-
- if (!rects_Intersect(&ballRect,&gMenuRect))
- Blit_Ball(&ballRect,&ballColor);
-
- if (tBallPtr->fLength)
- tBallPtr->fLength--;
-
- offset_rect(&ballRect,tBallPtr->fDelta.h,0);
- if (ballRect.left <= bounds.left)
- {
- offset_rect(&ballRect, bounds.left - ballRect.left,0);
- tBallPtr->fDelta.h = ABS(tBallPtr->fDelta.h);
- do {tBallPtr->fDelta.v = (tBallPtr->fDelta.v + (random() % 2)) % 5;} while (!tBallPtr->fDelta.v);
- }
- else if (ballRect.right >= bounds.right)
- {
- offset_rect(&ballRect, bounds.right - ballRect.right,0);
- tBallPtr->fDelta.h = -ABS(tBallPtr->fDelta.h);
- do {tBallPtr->fDelta.v = (tBallPtr->fDelta.v + (random() % 2)) % 5;} while (!tBallPtr->fDelta.v);
- }
-
- offset_rect(&ballRect,0,tBallPtr->fDelta.v);
- if (ballRect.top <= bounds.top)
- {
- offset_rect(&ballRect,0, bounds.top - ballRect.top);
- tBallPtr->fDelta.v = ABS(tBallPtr->fDelta.v);
- do {tBallPtr->fDelta.h = (tBallPtr->fDelta.h + (random() % 2)) % 5;} while (!tBallPtr->fDelta.h);
- }
- else if (ballRect.bottom >= bounds.bottom)
- {
- offset_rect(&ballRect,0, bounds.bottom - ballRect.bottom);
- tBallPtr->fDelta.v = -ABS(tBallPtr->fDelta.v);
- do {tBallPtr->fDelta.h = (tBallPtr->fDelta.h + (random() % 2)) % 5;} while (!tBallPtr->fDelta.h);
- }
- tBallPtr->fPosition = *(Point*) &ballRect;
-
- return noErr;
- }
-
- /**\
- |**| draw a ball
- \**/
-
- static void Draw_Ball(const Rect* pRectPtr,const RGBColor* pBallColorPtr)
- {
- RGBColor invertRGBColor = *pBallColorPtr;
- //
- // Set that color as the new color to use in drawing.
- //
- RGBForeColor(pBallColorPtr);
-
- //
- // Move pen to the new location, and paint the colored ball.
- //
- PaintOval (pRectPtr);
-
- //
- // Move the pen to the middle of the new ball position, for the text
- //
- MoveTo((short)(pRectPtr->left + kBallWidth/2 - kTextSize),
- (short)(pRectPtr->top + kBallHeight/2 + kTextSize/2 -1));
-
- //
- // Invert the color and draw the text there. This won’t look quite right in 1 bit
- // mode, since the foreground and background colors will be the same.
- // Color QuickDraw special cases this to not invert the color, to avoid
- // invisible drawing.
- //
- InvertColor(&invertRGBColor);
- RGBForeColor(&invertRGBColor);
-
- // (
- DrawString("\p;-)");
-
- InvertOval(&gOffscreenRect);
- }
-
- /**\
- |**| Blit a ball onscreen
- \**/
-
- static void Blit_Ball(const Rect *pBallRect,const RGBColor* pBallColorPtr)
- {
- UInt16 srcSkip = (*gOffscreenPixMap)->rowBytes & 0x3FFF;
- UInt16 dstSkip = (*gWindowPixMap)->rowBytes & 0x3FFF;
-
- UInt8 *srcBase = gOffscreenBasePtr +
- (srcSkip * (gOffscreenRect.top - (*gOffscreenPixMap)->bounds.top)) +
- ((gOffscreenRect.left - (*gOffscreenPixMap)->bounds.left) >> 3);
-
- UInt8 *dstBase = gWindowBasePtr +
- (dstSkip * (pBallRect->top - (*gWindowPixMap)->bounds.top));
-
- UInt16 r,c,pixelSize = (*gWindowPixMap)->pixelSize;
-
- UInt32 color32 = 0x00FFFFFF & (
- (pBallColorPtr->red << 16) ^
- (pBallColorPtr->green << 8) ^
- (pBallColorPtr->blue << 0)
- );
- UInt16 color16 = 0x7FFF & color32;
- UInt8 color8 = 0xFF & color16;
-
- switch (pixelSize)
- {
- case 1: // b/w
- case 2: // 4 colors
- case 4: // 16 colors
- break; // Sorry, Homey don't play that! (Yet!)
- case 8: // 256 colors
- dstBase += pBallRect->left - (*gWindowPixMap)->bounds.left;
- break;
- case 16: // thousand colors
- dstBase += (pBallRect->left - (*gWindowPixMap)->bounds.left) << 1;
- break;
- case 32: // million colors
- dstBase += (pBallRect->left - (*gWindowPixMap)->bounds.left) << 2;
- break;
- }
-
- for (r = gOffscreenRect.top;r < gOffscreenRect.bottom;r++)
- {
- UInt8 *srcPtr = srcBase,*dstPtr = dstBase;
- UInt8 data = *srcPtr++;
- for (c = gOffscreenRect.left;c < gOffscreenRect.right;c++)
- {
- UInt8 i = 7 - (c % 8);
-
- switch (pixelSize)
- {
- case 1: // b/w
- case 2: // 4 colors
- case 4: // 16 colors
- break; // Sorry, Homey don't play that! (Yet!)
- case 8: // 256 colors
- if ((data >> i) & 1) // source bit is set
- *dstPtr = color8;
- dstPtr++;
- break;
- case 16: // b/w depth
- if ((data >> i) & 1) // source bit is set
- *(UInt16*)dstPtr = color16;
- dstPtr += 2;
- break;
- case 32: // b/w depth
- if ((data >> i) & 1) // source bit is set
- *(UInt32*)dstPtr = color32;
- dstPtr += 4;
- break;
- }
-
- if (i == 0)
- data = *srcPtr++;
- }
- srcBase += srcSkip;
- dstBase += dstSkip;
- }
- }
-
- /**\
- |**| Test to see if rectangles intersect
- \**/
-
- static Boolean rects_Intersect(const Rect* pRect1,const Rect* pRect2)
- {
- if (pRect1->bottom <= pRect2->top)
- return false;
- if (pRect1->top >= pRect2->bottom)
- return false;
- if (pRect1->right <= pRect2->left)
- return false;
- if (pRect1->left >= pRect2->right)
- return false;
- return true;
- }
-
- /**\
- |**| move a rectangle
- \**/
-
- static void offset_rect(Rect *r,const short dh,const short dv)
- {
- r->top += dv;
- r->left += dh;
- r->bottom += dv;
- r->right += dh;
- }
-
- /**\
- |**| generate a random number +/- 32768
- \**/
-
- static SInt16 random()
- {
- static SInt32 state = 314159;
-
- state = ((state * 1103515245) + 12345 ) & 0x7fffffff;
-
- return ((state >> 6) & 0xffff);
- }
-
-